package util;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 数字操作工具类
 * @author wanglei
 * @date 2019/5/21
 * */
public class NumberUtil {

    private static List<String> specialStrList = new ArrayList<>();

    private static Pattern pattern = Pattern.compile("\\pP");

    static{
        specialStrList.add("0");
        specialStrList.add("0.0");
        specialStrList.add("0.00");
    }

    // ============================ 随机数 =======================================================//

    /**
     * 生成一组随机数，总数大小确定，分隔数值确定
     *
     * @param total 总数
     * @param splitCount 分割数
     * */
    public static List<Integer> splitNumbers(int total, int splitCount){
        if(splitCount >= total){
            System.out.println("分割数不能大于等于总数");
        }
        return splitRedPacket(total, splitCount, 0, total-splitCount);
    }

    /**
     *
     * @param total
     *            总金额
     * @param splitCount
     *            个数
     * @param min
     *            最小金额
     * @param max
     *            最大金额
     */
    public static List<Integer> splitRedPacket(int total, int splitCount, int min, int max) {
        System.out.println("总金额：	" + total);
        System.out.println("个数：	" + splitCount);
        System.out.println("最小金额：	" + min);
        System.out.println("最大金额：	" + max);

        if(max * splitCount < total || splitCount * min > total){
            System.out.println("最小金额太大或者最大金额太小，无法生成随机数");
            return null;
        }

        ArrayList<Integer> al = new ArrayList<Integer>();
        Random random = new Random();

        if ((splitCount & 1) == 1) {// 奇数个红包，需要单独将其中一个红包先生成，以保证后续算法拆分份数为偶数。
            System.out.println("红包个数" + splitCount + "是奇数，单独生成一个红包");
            int num = 0;
            do {
                num = random.nextInt(max);
                // num = (total - num) % (splitCount / 2) + num; //
                // 将后面算法拆分时的余数加入到这个随机值中。
                System.out.println("单个的随机红包为：" + num);
            } while (num >= max || num <= min);

            total = total - num;
            al.add(num);
        }
        int couples = splitCount >> 1;
        int perCoupleSum = total / couples;

        if ((splitCount & 1) == 1) {
            System.out.println("处理后剩余的金额为：" + total);
        }
        System.out.println("将" + total + "元拆分为" + couples + "对金额，每对总额：" + perCoupleSum);

        for (int i = 0; i < couples; i++) {
            Boolean finish = true;
            int num1 = 0;
            int num2 = 0;
            do {
                num1 = random.nextInt(max);
                num2 = perCoupleSum - num1;
                if (!al.contains(num1) && !al.contains(num2)) {
                    if (i == 0) {
                        num1 = (total - couples * perCoupleSum) + num1;
                    }
                }
            } while (num1 < min || num1 > max || num2 < min || num2 > max);
            al.add(num1);
            al.add(num2);
        }
        int check_num = 0;
        System.out.println(Arrays.toString(al.toArray()));

        for (int x : al) {
            check_num = check_num + x;
        }
        System.out.println("验证总和：" + check_num);
        return al;
    }

    /**
     * 不重复的随机数
     *
     * @param num 生成多少个随机数
     *
     * @date 2022/4/4
     * */
    public static List<Integer> randomNoRepeat(int min, int max, int num){
        List<Integer> randomList = new ArrayList<>();
        while (randomList.size() < num) {
            Random random = new Random();
            int randomNum = random.nextInt(max) % (max - min + 1) + min;
            if(!randomList.contains(randomNum)){
                randomList.add(randomNum);
            }
        }
        return randomList;
    }

    /**
     * 根据年份和月份，生成随机的连续天数
     *
     * @param days 连续的天数
     * @author wanglei
     * @date 2011/11/29
     * */
    public static List<Integer> randomSeriesDay(Integer year, Integer month, Integer days){
        // 获取当月的总天数
        Integer days_of_months = DateUtil.getDays(year, month);
        // 起始数
        Integer start = randomInt(1, days_of_months + 2 - days);
        List<Integer> nums = new ArrayList<>();
        for(int i=1; i<=days; i++){
            nums.add(start);
            start++;
        }
        return nums;
    }

    /**
     * 生成一个随机整数，包含最小值和最大值。最小值为0的话，不包含最大值
     * @param min 最小值
     * @param max 最大值
     *
     * @author wanglei
     * @date 2021/11/29
     * */
    public static Integer randomInt(int min, int max){
        Random random = new Random();
        return random.nextInt(max) % (max - min + 1) + min;
    }

    /**
     * 生成一个从负数到正数的随机整数
     *
     * @param scale 数据范围，比如输入50， 生成的随机数就在 [-50, 50]之间
     * @author wanglei
     * @date 2021/11/29
     * */
    public static Integer randomMinus2Plus(int scale){
        Integer num = randomInt(0, scale);
        Integer flag = randomInt(0, 2);
        String symbol = flag.equals(0) ? "-" : "";
        return Integer.parseInt(symbol+num);
    }

    /**
     * 生成一个随机带整数位的小数，指定最大值和最小值范围
     *
     * @author wanglei
     * @date 2021/11/29
     * */
    public static String randomDec(String minStr, String maxStr){
        // 分别提取整数部分和小数部分
        int minInt = Integer.parseInt(minStr.split("\\.")[0]);
        String minDec = minStr.split("\\.")[1];
        int maxInt = Integer.parseInt(maxStr.split("\\.")[0]);
        String maxDec = maxStr.split("\\.")[1];

        // 小数位数补零
        int minDecLength = minDec.length();
        int maxDecLength = maxDec.length();
        if(minDecLength > maxDecLength){
            int lengthCha = minDecLength - maxDecLength;
            for(int i=1; i<=lengthCha; i++){
                maxDec += "0";
            }
        }
        else if(minDecLength < maxDecLength){
            int lengthCha = maxDecLength - minDecLength;
            for(int i=1; i<=lengthCha; i++){
                minDec += "0";
            }
        }

        // 定义小数位的最大位数的最大值
        String limitDec = "";
        for(int i=1; i<=maxDec.length(); i++){
            limitDec += "9";
        }
        int limitInt = Integer.parseInt(limitDec.toString());


        // 定义生成的整数部分和小数部分
        Integer inte;
        String dec;
        // 经度定义
        inte = randomInt(minInt, maxInt); // 整数
        // 如果整数等于最大值或最小值的整数部分，则生成小数部分需要重新
        if(minInt == maxInt){ // 最大值和最小值相同
            dec = randomInt(Integer.parseInt(minDec), Integer.parseInt(maxDec)).toString();
        }
        else if(inte.equals(minInt)){ // 等于最小值
            dec = randomInt(Integer.parseInt(minDec), limitInt).toString();
        }
        else if(inte.equals(maxInt)){ // 等于最大值
            dec = randomInt(0, Integer.parseInt(maxDec)).toString();
        }
        else { // 介于最大值和最小值中间
            dec = randomInt(0, limitInt).toString();
        }
        // 小数部分补零
        dec = addZeroForNum(dec, minDec.length());
        // 去除尾数的0
        dec = deleteZeroAfter(dec);

        return inte + "." + dec;
    }

    /**
     * 生成一个0-1之间的随机小数，位数不超过15位。
     * @param bit 保留几位小数
     * */
    public static double randomDouble(int bit){
        Random random = new Random();
        return Double.parseDouble(String.valueOf(random.nextDouble()).substring(0, bit+2));
    }

    // ============================ 公共类 =======================================================//

    /**
     * 将带”E“的数据。例如”6.0E9“转换为正常数据
     *
     * @author wanglei
     * @date 2021/6/25
     * */
    public static String number2Plain(String str){
        return new BigDecimal(str).toPlainString();
    }

    /**
     * 数字后面去零
     *
     * @author wanglei
     * @date 2021/11/29
     * */
    public static String deleteZeroAfter(String str){
        int strLen = str.length();
        String result = str;
        for(int i=strLen-1; i>0; i--){
            String temp = result.substring(result.length()-1);
            if(temp.equals("0")){
                result = result.substring(0, i);
            }
        }
        return result;
    }

    /**
     * 数字前面补零
     *
     * @author wanglei
     * @date 2021/4/29
     * */
    public static String addZeroForNum(String str, int strLength) {
        int strLen = str.length();
        StringBuffer sb = null;
        while (strLen < strLength) {
            sb = new StringBuffer();
            sb.append("0").append(str);// 左补0
            // sb.append(str).append("0");//右补0
            str = sb.toString();
            strLen = str.length();
        }
        return str;
    }

    /**
     * 格式化金额为两位小数
     * */
    public static BigDecimal formatBigDecimal(BigDecimal value){
        DecimalFormat dFormat = new DecimalFormat("#.00");
        String format = dFormat.format(value);
        return new BigDecimal(format);
    }

    /**
     * 格式化数字，不保留0，如果为空返回0
     * @param str 数字的字符串
     * @return 不保留0的数字字符串，比如2.30返回 2.3
     * */
    public static String formatNumberNoZero(String str){
        return formatNumberWithFormat(str, "#.##");
    }

    /**
     * 格式化数字，可以指定格式化模板，例如 #.##，#.00
     * @param str 要格式化的数字
     * @param format 格式化模板
     * @return 格式化好的数字字符串
     * */
    private static String formatNumberWithFormat(String str, String format){
        if(str != null){
            str = str.trim();
            for(String specialStr : specialStrList){
                if(specialStr.equals(str)){
                    return "0";
                }
            }
            if(isNumeric(str)){
                // 如果是05这样的数字，直接返回。
                if(isPrefixWithZero(str)){
                    return str;
                }
                DecimalFormat dFormat = new DecimalFormat(format);
                dFormat.setRoundingMode(RoundingMode.HALF_UP);//四舍五入必须加这段
                String formatStr = dFormat.format(new BigDecimal(str));
                return new BigDecimal(formatStr).toString();
            }
            return str;
        }else{
            return "0";
        }
    }

    /**
     * 判断前缀为0的数字，比如001，02，03这样的
     * @param str 数字字符串
     * @return true：是前缀带0的字符串，false：不是前缀带0的字符串
     * */
    public static boolean isPrefixWithZero(String str){
        str = str.trim();
        if(str.length()>0){
            if(isNumeric(str)){
                if(str.length()>=2){
                    String sub1 = str.substring(0,1);
                    String sub2 = str.substring(1,2);
                    // 判断逻辑：第一位是0，第二位不是.的数字，长度要大于等于2
                    return sub1.equals("0") && !sub2.equals(".");
                }
            }
        }
        return false;
    }

    /**
     * 去除数字后面无用的零
     * */
    public static String removeEndZero(double value){
        NumberFormat nf = NumberFormat.getInstance();
        return nf.format(value);
    }

    /**
     * 格式化金额显示 小数点后面的0删除掉
     * @param bigDecimal 金额bigDecimal
     * @return
     */
    public static String formatMoneyString(BigDecimal bigDecimal){
        if (bigDecimal==null){
            return "0";
        }
        DecimalFormat decimalFormat = new DecimalFormat("###,##0.00");
        String res = decimalFormat.format(bigDecimal).replace(".00","");
        if (res.contains(".")){
            res = trimRight(res,"0");
        }
        return res == null || "".equals(res) ? "0" : res;
    }

    /**
     * 删除左边字符
     * @param param 参数
     * @param target 要删除的字符
     * @return
     */
    public static String trimLeft(String param,String target){
        if (param != null && target != null && !"".equals(target)){
            while (param.startsWith(target)){
                param = param.replaceFirst(target,"");
            }
        }
        return param;
    }

    /**
     * 循环删除右边指定字符
     * @param param 输入
     * @param target 删除目标
     * @return
     */
    public static String trimRight(String param,String target){
        if (param != null && target != null && !"".equals(target)){
            while (param.endsWith(target)){
                param = param.substring(0,param.length() - target.length());
            }
        }
        return param;
    }

    /**
     * 删除 右边的标点符号
     * @param param 原字符串
     * @return
     */
    public static String trimRightSymbol(String param){
        if (param == null || "".equals(param)){
            return "";
        }
        char c[] = param.toCharArray();
        int count = 0;
        for (int i = c.length-1; i >= 0; i--) {
            Matcher matcher = pattern.matcher(String.valueOf(c[i]));
            if (matcher.matches()) {
                count++;
            }else {
                break;
            }
        }
        if (count == c.length){
            return "";
        }
        if (count > 0){
            return param.substring(0,param.length() - count);
        }
        return param;
    }

    /**
     * 删除两边的标点符号
     * @param param 输入字符串
     * @param ignore 忽略的标点符号
     * @return
     */
    public static String trimSymbol(String param,String... ignore){
        if (param == null || "".equals(param)){
            return "";
        }
        param = param.trim();
        char c[] = param.toCharArray();
        int start = 0;
        int end = c.length;
        HashSet<String> set = new HashSet<>();
        set.addAll(Arrays.asList(ignore));
        for (int i = c.length-1; i >= 0; i--) {
            if (set.contains(String.valueOf(c[i]))) {
                break;
            }
            Matcher matcher = pattern.matcher(String.valueOf(c[i]));
            if (matcher.matches()) {
                end --;
            }else {
                break;
            }
        }
        for (int i = 0; i < c.length; i++) {
            if (set.contains(String.valueOf(c[i]))) {
                break;
            }
            Matcher matcher = pattern.matcher(String.valueOf(c[i]));
            if (matcher.matches()) {
                start ++;
            }else {
                break;
            }
        }
        if (start < end){
            return param.substring(start,end);
        }else {
            return  "";
        }
    }

    /**
     * 字符串格式化为金额格式
     * @param string
     * @return
     */
    public static String formatMoneyByString(String string){
        BigDecimal bigDecimal = null;
        if (isNumeric(string)){
            bigDecimal = new BigDecimal(string);
        }
        return formatMoneyString(bigDecimal);
    }

    /**
     * BigDecimal的除法, decimal 是保留几位小数
     * */
    public static BigDecimal divide(BigDecimal a, BigDecimal b, int decimal){
        return a.divide(b, decimal, RoundingMode.HALF_UP);
    }

    /**
     * 利用正则表达式判断字符串是否是数字
     * @param str 数字字符串
     * @return true：是数字，false：不是数字
     * */
    public static boolean isNumeric(String str){
        if(str!=null && str.trim().length()>0){
            // 清除两边空格
            str = str.trim();
            // 清除货币里的逗号
            str = str.replace(",", "");
            return Pattern.matches("(-?\\d+(\\.\\d+)?)", str);
        }
        return false;
    }

    /**
     * BigDecimal的减法，
     * @param minuend 被减数
     * @param subtract 减数
     * @return
     */
    public static BigDecimal subtraction(BigDecimal minuend, BigDecimal subtract){
        return minuend.subtract(subtract);
    }

    /**
     * 小数转换为百分比
     * */
    public static String decimal2Percent(BigDecimal decimal){
        BigDecimal value = formatBigDecimal(decimal.multiply(new BigDecimal(100)));
        if (value.toString().equals("0.00")){
            return "0%";
        }
        String temp = trimRight(trimRight(value.toString(),"0"),".");
        return temp + "%";
    }

    /**
     * 判断是否奇数
     * */
    public static boolean isOdd(int a){
        return a % 2 == 1;
    }

    // ============================ 私有类 =======================================================//
}
